import { AcGameObject } from "./AcGameObject";
import { Wall } from "./Wall";
import { Snake } from "./Snake";

export class GameMap extends AcGameObject {
    constructor(ctx, parent,store) {//全局变量当成参数传入
        super();
        this.store = store;//全局变量赋值
        this.ctx = ctx;
        this.parent = parent;
        this.L = 0;

        this.rows = 13;
        this.cols = 14;

        this.walls = [];

        this.inner_walls_count = 20;
        this.walls = [];

        this.snakes = [
            new Snake({ id: 0, color: "#4876EC", r: this.rows - 2, c: 1 }, this),
            new Snake({ id: 1, color: "#F94848", r: 1, c: this.cols - 2 }, this),
        ];

    }

    // check_connectivity(g, sx, sy, tx, ty) {
    //     if (sx == tx && sy == ty) return true;
    //     g[sx][sy] = true;

    //     let dx = [-1, 0, 1, 0], dy = [0, 1, 0, -1];
    //     for (let i = 0; i < 4; i++) {
    //         let x = sx + dx[i], y = sy + dy[i];
    //         if (!g[x][y] && this.check_connectivity(g, x, y, tx, ty))
    //             return true;
    //     }
    //     return false;
    // }
    crete_walls() {//这里地图在后端生成并传入全局变量，所以这里只要拿出来渲染
        // console.log(this.store.state.pk);//查看全局变量
        const g =this.store.state.pk.gamemap;//从全局变量中取出地图数组
        // console.log(g);
        for (let r = 0; r < this.rows; r++) {//渲染出来
            for (let c = 0; c < this.cols; c++) {
                if (g[r][c]) {
                    this.walls.push(new Wall(r, c, this));
                }
            }
        }
        return true;
    }

    // add_listening_events() {
    //     const [snake0, snake1] = this.snakes;
    //     this.ctx.canvas.focus();
    //     this.ctx.canvas.addEventListener("keydown", e => {
    //         if (e.key === 'w') snake0.set_direction(0);
    //         else if (e.key === 'd') snake0.set_direction(1);
    //         else if (e.key === 's') snake0.set_direction(2);
    //         else if (e.key === 'a') snake0.set_direction(3);
    //         else if (e.key === 'ArrowUp') snake1.set_direction(0);
    //         else if (e.key === 'ArrowRight') snake1.set_direction(1);
    //         else if (e.key === 'ArrowDown') snake1.set_direction(2);
    //         else if (e.key === 'ArrowLeft') snake1.set_direction(3);
    //         // console.log(e);
    //     });
    // }
    add_listening_events() {

        if (this.store.state.record.is_record) {//如果当前是回放界面
            let k = 0;//存已经操作的步骤
            const a_steps = this.store.state.record.a_steps;//从全局变量中取出ab的操作数组和失败者
            const b_steps = this.store.state.record.b_steps;
            const loser = this.store.state.record.record_loser;
            const [snake0, snake1] = this.snakes;//取出蛇（实际上本类有个对象也存在全局变量中，也可以从那里拿蛇）
            const interval_id = setInterval(()=>{//存下这个操作的id，方便后面取消掉
                if (k >= a_steps.length - 1) {//-1是因为蛇的最后一步是不走的，因为总有一条蛇死亡了
                    if (loser === "all" || loser === "A") {//标记死亡蛇
                        snake0.status = "die";
                    }
                    if (loser === "all" || loser === "B") {
                        snake1.status = "die";
                    }
                    clearInterval(interval_id);//录像播放结束了，需要取消掉循环（根据上面存的id来取消）
                } else {//ab蛇动一下
                    snake0.set_direction(parseInt(a_steps[k]));
                    snake1.set_direction(parseInt(b_steps[k]));
                }
                k ++ ;
            }, 300);//每300毫秒执行一下里面的函数（因为设定是每秒走五格，走一格需要200ms，我们给出300ms）
        } else {//如果当前是游戏界面
            this.ctx.canvas.focus();//键盘画布聚焦
            this.ctx.canvas.addEventListener("keydown", e => {//监听键盘
                let d = -1;//记录方向
                if (e.key === 'w') d = 0;
                else if (e.key === 'd') d = 1;
                else if (e.key === 's') d = 2;
                else if (e.key === 'a') d = 3;
                if (d >= 0) {//输入合法
                    this.store.state.pk.socket.send(JSON.stringify({//向链接发送json转字符串的信息
                        event: "move",//确定事件类型
                        direction: d,
                    }));
                }
            });
        }
    }




    start() {
        // for (let i = 0; i < 1000; i++)
        //     if (this.crete_walls())
        //         break;
        this.crete_walls();//这里只调用一次就行，因为1000次在后端执行了
        this.add_listening_events();//这里面绑定了监听器，以后只要键盘输入，就能直接自动触发监听函数
    }

    update_size() {
        this.L = parseInt(Math.min(this.parent.clientWidth / this.cols, this.parent.clientHeight / this.rows));
        this.ctx.canvas.width = this.L * this.cols;
        this.ctx.canvas.height = this.L * this.rows;
    }

    check_ready() { //判断两条蛇是否都准备好下一回合了
        for (const snake of this.snakes) {
            if (snake.status !== "idle") return false;
            if (snake.direction === -1) return false;
        }
        return true;
    }


    check_valid(cell) {  // 检测目标位置是否合法：没有撞到两条蛇的身体和障碍物
        for (const wall of this.walls) {
            if (wall.r === cell.r && wall.c === cell.c)
                return false;
        }

        for (const snake of this.snakes) {
            let k = snake.cells.length;
            if (!snake.check_tail_increasing()) {  // 当蛇尾会前进的时候，蛇尾不要判断
                k--;
            }
            for (let i = 0; i < k; i++) {
                if (snake.cells[i].r === cell.r && snake.cells[i].c === cell.c)
                    return false;
            }
        }

        return true;
    }


    next_step() { //让两条蛇进入下一回合
        for (const snake of this.snakes) {
            snake.next_step();
        }
    }

    update() {
        this.update_size();//每次都要更新大小，因为窗口可能在不断缩小放大
        if (this.check_ready()) {
            this.next_step();
        }
        this.render();
    }

    render() {
        const color_even = "#AAD752", color_odd = "#A2D048";
        for (let r = 0; r < this.rows; r++) {
            for (let c = 0; c < this.cols; c++) {
                if ((r + c) % 2 == 0) {
                    this.ctx.fillStyle = color_even;
                } else {
                    this.ctx.fillStyle = color_odd;
                }
                this.ctx.fillRect(c * this.L, r * this.L, this.L, this.L);
            }
        }
    }


}
